package vincent.com.layouttest;

import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import vincent.com.layouttest.adapter.BluetoothDeviceAdapter;
import vincent.com.layouttest.util.LogUtil;
import vincent.com.layouttest.util.ReflectHelper;
import vincent.com.layouttest.view.SwitchButton;

/**
 * Created by zhengwenchen on 2016/5/9.
 */
public class BluetoothActivity extends ColorStatusActivity implements View.OnClickListener{

    private Button bt_switch;
    private ListView bonded_list, avail_list;

    private BluetoothDeviceAdapter bondedAdapter, availAdapter;

    private UUID DEFAULT_UUID = UUID.fromString("00001101-0000-1000-8000-00805FFB74FB");

    //蓝牙适配器
    BluetoothAdapter btAdapter;

    Receiver mReceiver;

    private WorkHandler mWorkHandler;

    private BluetoothSocket mCurrentSocket;

    private View bondedListHeader, availListHeader;

    private BluetoothHeadset mHeadsetService;
    private BluetoothA2dp mA2dpService;

    private boolean mConnectAfterBond = false;

    private Button startDiscovery;

    private SwitchButton switchBtn;

    private boolean isProxyBounded = false;

    @Override
    public View onCreateView(ViewGroup rootView) {
        return LayoutInflater.from(this).inflate(R.layout.activity_bluetooth, rootView, true);
    }

    static class WorkHandler extends Handler {
        static final int ACTION_CONNECT = 0x01;

        private final WeakReference<BluetoothActivity> ref;

        public WorkHandler(Looper looper, BluetoothActivity fragment) {
            super(looper);
            ref = new WeakReference<BluetoothActivity>(fragment);
        }

        @Override
        public void handleMessage(Message msg) {
            final BluetoothActivity activity = ref.get();
            if (activity == null) {
                return;
            }

            switch (msg.what) {
                case ACTION_CONNECT:
                    BluetoothDevice dev = (BluetoothDevice) msg.obj;
                    activity.connect(dev);
            }
        }
    }

    protected HandlerThread mWorker;

    protected int getWorkLooperThreadPriority() {
        return Process.THREAD_PRIORITY_BACKGROUND;
    }

    public Looper getWorkLooper() {
        if (mWorker == null) {
            mWorker = new HandlerThread("work_handler", getWorkLooperThreadPriority());
            mWorker.start();
        }
        return mWorker.getLooper();
    }

    class Receiver extends BroadcastReceiver{

        WeakReference<BluetoothActivity> ref;

        Receiver(BluetoothActivity activity){
            ref = new WeakReference<BluetoothActivity>(activity);
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            BluetoothActivity instance = ref.get();
            if(instance == null){
                return;
            }

            String action = intent.getAction();
            if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)){
                int currentState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
                int oldState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, 0);
                LogUtil.i("czw_bluetooth", "当前蓝牙状态--->" + currentState + " | 前一个蓝牙状态--->" + oldState);
                instance.checkBtState(currentState);
            }else if(BluetoothDevice.ACTION_FOUND.equals(action)){
                //只会发现还未配对过的设备
                // Get the BluetoothDevice object from the Intent
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                BluetoothClass btClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS);
                // Add the name and address to an array adapter to show in a ListView
                instance.onDeviceFound(device, btClass);
            }else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                String name = device.getName();
                LogUtil.i("czw_bluetooth", "device name: " + name + " | address: " + device.getAddress());
                int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
                switch (state) {
                    case BluetoothDevice.BOND_NONE:
                        LogUtil.i("czw_bluetooth", "BOND_NONE 删除配对");
                        onDeviceBondNone(device);
                        break;
                    case BluetoothDevice.BOND_BONDING:
                        LogUtil.i("czw_bluetooth", "BOND_BONDING 正在配对");
                        onDeviceBonding(device);
                        break;
                    case BluetoothDevice.BOND_BONDED:
                        LogUtil.i("czw_bluetooth", "BOND_BONDED 配对成功");
                        onDeviceBonded(device);
                        break;
                }
            }else if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                instance.onDeviceConnected(device);
            } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                instance.onDeviceDisconnected(device);
            }
        }
    }

    //删除配对
    public void onDeviceBondNone(BluetoothDevice device){
        Set<BluetoothDevice> devices = btAdapter.getBondedDevices();
        if(devices.size() > 0){
            BluetoothDevice[] devices1 = new BluetoothDevice[devices.size()];
            devices.toArray(devices1);

            bondedAdapter.setData(devices1);
        }else {
            bondedAdapter.clear();
        }

        updateListState();
    }

    //正在配对
    public void onDeviceBonding(BluetoothDevice device){

        updateListState();
    }

    //配对成功
    public void onDeviceBonded(BluetoothDevice device){
        Set<BluetoothDevice> devices = btAdapter.getBondedDevices();
        if (devices.size() > 0) {
            BluetoothDevice[] devices1 = new BluetoothDevice[devices.size()];
            devices.toArray(devices1);

            bondedAdapter.setData(devices1);
        }

        availAdapter.removeDevice(device);

        updateListState();

        if(mConnectAfterBond){
            mConnectAfterBond = false;
            connect(device);
        }
    }

    //蓝牙设备已连接
    public void onDeviceConnected(BluetoothDevice device){
        LogUtil.i("czw_bluetooth", "设备已连接--->" + device.getName() + " | " + device.getAddress());
        bondedAdapter.updateConnectedAddress(device.getAddress());
        availAdapter.updateConnectedAddress(device.getAddress());

        updateListState();
    }

    //蓝牙设备已断开
    public void onDeviceDisconnected(BluetoothDevice device){
        LogUtil.i("czw_bluetooth", "设备已断开--->" + device.getName() + " | " + device.getAddress());
        bondedAdapter.clearConnectAddress(device);
        availAdapter.clearConnectAddress(device);

        updateListState();
    }

    public void updateListState(){
        if(bondedAdapter.getCount() > 0){
            bondedListHeader.setVisibility(View.VISIBLE);
        }else{
            bondedListHeader.setVisibility(View.GONE);
        }

        if(availAdapter.getCount() > 0){
            availListHeader.setVisibility(View.VISIBLE);
        }else{
            availListHeader.setVisibility(View.GONE);
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        init();
        initView();
    }

    public void init(){
        btAdapter = BluetoothAdapter.getDefaultAdapter();

        mWorkHandler = new WorkHandler(getWorkLooper(), this);

        mReceiver = new Receiver(this);
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        filter.addAction(BluetoothDevice.ACTION_FOUND);
        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
        filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        registerReceiver(mReceiver, filter);

        if(btAdapter == null){
            Toast.makeText(this, "无可用蓝牙适配器", Toast.LENGTH_SHORT).show();
            finish();
            return;
        }

        bt_switch = (Button)findViewById(R.id.bt_switch);
        bonded_list = (ListView)findViewById(R.id.matched_list);
        avail_list = (ListView)findViewById(R.id.avail_list);

        startDiscovery = (Button)findViewById(R.id.scan);
        startDiscovery.setOnClickListener(this);

        availListHeader = findViewById(R.id.avail_list_header);
        bondedListHeader = findViewById(R.id.bonded_list_header);

        switchBtn = (SwitchButton)findViewById(R.id.switch_btn);
        switchBtn.setOnClickListener(this);

        bondedAdapter = new BluetoothDeviceAdapter(this, BluetoothDeviceAdapter.BONDED_LIST_TYPE);
        bonded_list.setAdapter(bondedAdapter);

        availAdapter = new BluetoothDeviceAdapter(this, BluetoothDeviceAdapter.AVAIL_LIST_TYPE);
        avail_list.setAdapter(availAdapter);

        bt_switch.setOnClickListener(this);

        bonded_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                BluetoothDevice dev = (BluetoothDevice) bondedAdapter.getItem(position);

                if(dev != null){
                    onDevItemClick(dev);
                }

                /*mWorkHandler.removeMessages(WorkHandler.ACTION_CONNECT);
                Message.obtain(mWorkHandler, WorkHandler.ACTION_CONNECT, dev).sendToTarget();*/
            }
        });

        avail_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                BluetoothDevice dev = (BluetoothDevice) availAdapter.getItem(position);

                if(dev != null){
                    onDevItemClick(dev);
                }

                /*mWorkHandler.removeMessages(WorkHandler.ACTION_CONNECT);
                Message.obtain(mWorkHandler, WorkHandler.ACTION_CONNECT, dev).sendToTarget();*/
            }
        });

        // Establish connection to the proxy.
        boundProxy();
    }

    public void boundProxy(){
        if(!isProxyBounded && btAdapter.isEnabled()){
            btAdapter.getProfileProxy(this, mHeadsetListener, BluetoothProfile.HEADSET);
            btAdapter.getProfileProxy(this, mA2dpListener, BluetoothProfile.A2DP);

            isProxyBounded = true;
        }
    }

    public void onDevItemClick(BluetoothDevice device){

//        boolean isDevConnected = (boolean) ReflectHelper.callDeclaredMethod(device, "isConnected", null, null);
        boolean isDevConnected = getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED ? true : false;

        if(isDevConnected){
            disconnect(device);
        }else{
            int connectState = device.getBondState();
            switch (connectState) {
                // 未配对
                case BluetoothDevice.BOND_NONE:
                    mConnectAfterBond = true;
                    bond(device);
                    break;
                // 已配对
                case BluetoothDevice.BOND_BONDED:
                    connect(device);
                    break;
            }
        }
    }

    public int getConnectionStatus(BluetoothDevice device){
        if(mHeadsetService == null && mA2dpService == null){
            return BluetoothProfile.STATE_DISCONNECTED;
        }

        if(mHeadsetService != null){
            List<BluetoothDevice> deviceList = mHeadsetService.getConnectedDevices();

            if(deviceList != null && deviceList.size() > 0){
                for(BluetoothDevice dev : deviceList){
                    if(dev.getAddress().equals(device.getAddress())){
                        return mHeadsetService.getConnectionState(device);
                    }
                }
            }
        }

        if(mA2dpService != null){
            List<BluetoothDevice> deviceList = mA2dpService.getConnectedDevices();

            if(deviceList != null && deviceList.size() > 0){
                for(BluetoothDevice dev : deviceList){
                    if(dev.getAddress().equals(device.getAddress())){
                        return mA2dpService.getConnectionState(device);
                    }
                }
            }
        }

        return BluetoothProfile.STATE_DISCONNECTED;
    }

    private BluetoothProfile.ServiceListener mA2dpListener = new BluetoothProfile.ServiceListener() {
        public void onServiceConnected(int profile, BluetoothProfile proxy) {
            LogUtil.i("czw_bluetooth", "onServiceConnected a2dp profile--->" + profile);
            mA2dpService = (BluetoothA2dp) proxy;

            bondedAdapter.onServiceConnected(profile, proxy);
            availAdapter.onServiceConnected(profile, proxy);
        }

        public void onServiceDisconnected(int profile) {
            LogUtil.i("czw_bluetooth", "onServiceDisconnected a2dp profile--->" + profile + " 已断开连接");
            mA2dpService = null;

            bondedAdapter.onServiceDisconnected(profile);
            availAdapter.onServiceDisconnected(profile);
        }
    };

    //获取当前各种设备proxy的已连接蓝牙设备
    private BluetoothProfile.ServiceListener mHeadsetListener = new BluetoothProfile.ServiceListener() {
        public void onServiceConnected(int profile, BluetoothProfile proxy) {
            LogUtil.i("czw_bluetooth", "onServiceConnected profile--->" + profile);
            mHeadsetService = (BluetoothHeadset) proxy;

            bondedAdapter.onServiceConnected(profile, proxy);
            availAdapter.onServiceConnected(profile, proxy);
            List<BluetoothDevice> devices = proxy.getConnectedDevices();

            if (devices != null && devices.size() > 0) {
                for (BluetoothDevice dev : devices) {
                    LogUtil.i("czw_bluetooth", "name--->" + dev.getName() + " | address--->" + dev.getAddress());

                    bondedAdapter.updateConnectedAddress(dev.getAddress());
                }
            }
        }

        public void onServiceDisconnected(int profile) {
            LogUtil.i("czw_bluetooth", "onServiceDisconnected profile--->" + profile + " 已断开连接");
            mHeadsetService = null;

            bondedAdapter.onServiceDisconnected(profile);
            availAdapter.onServiceDisconnected(profile);
        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(mReceiver != null){
            unregisterReceiver(mReceiver);
        }

        //关闭耳机代理连接
        if(isProxyBounded && mHeadsetService != null){
            btAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mHeadsetService);
            mHeadsetService = null;
        }

        //关闭A2dp代理连接
        if(isProxyBounded && mA2dpService != null){
            btAdapter.closeProfileProxy(BluetoothProfile.A2DP, mA2dpService);
            mA2dpService = null;
        }

        bondedAdapter.onDestory();
        availAdapter.onDestory();
    }

    public void initView(){
        checkBtState(0);
    }

    @Override
    public String getToolbarTitle() {
        return "蓝牙";
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.bt_switch:
                toggleBluetooth();
                break;
            case R.id.scan:
                startDiscoverDevices();
                break;
            case R.id.switch_btn:
                toggleBluetooth();
                break;
        }
    }

    public void toggleBluetooth(){
        if(btAdapter.isEnabled()){
            btAdapter.disable();
        }else{
            btAdapter.enable();
        }
    }

    public void checkBtState(int state){
        if (BluetoothAdapter.STATE_ON == state) {
            bt_switch.setText("关闭蓝牙设备");
            onBluetoothOpen();
            return;
        }

        if (BluetoothAdapter.STATE_OFF == state) {
            bt_switch.setText("开启蓝牙设备");
            onBluetoothOff();
            return;
        }

        if(btAdapter.isEnabled()){
            bt_switch.setText("关闭蓝牙设备");
            onBluetoothOpen();
        }else{
            bt_switch.setText("开启蓝牙设备");
            onBluetoothOff();
        }
    }

    public void onBluetoothOpen(){
        boundProxy();

        startDiscoverDevices();
        switchBtn.setOpen(true);

        Set<BluetoothDevice> bondedList = btAdapter.getBondedDevices();

        if (bondedList != null && bondedList.size() > 0) {

            BluetoothDevice[] devices = new BluetoothDevice[bondedList.size()];
            bondedList.toArray(devices);
            List<BluetoothDevice> deviceList = new ArrayList<>();

            Collections.addAll(deviceList, devices);
            bondedAdapter.setData(deviceList);
        }

        updateListState();
    }

    public void onBluetoothOff(){
        cancelDiscover();
        switchBtn.setOpen(false);

        if(bondedAdapter != null){
            bondedAdapter.clear();
        }

        if(availAdapter != null){
            availAdapter.clear();
        }

        updateListState();
    }

    public void onDeviceFound(BluetoothDevice device, BluetoothClass btClass) {
        LogUtil.i("czw_bluetooth", "发现设备 name--->" + device.getName() + " | 地址--->" + device.getAddress());

        int state = device.getBondState();
        if(BluetoothDevice.BOND_BONDED != state){
            availAdapter.addDevice(device);
            updateListState();
        }
    }

    //绑定配对
    private boolean bond(BluetoothDevice device){
        LogUtil.i("czw_bluetooth", "bond--->配对设备，" + device.getName()+"|"+device.getAddress());
        boolean rs = (boolean) ReflectHelper.callDeclaredMethod(device, "createBond", null, null);
        return rs;
    }

    //创建耳机连接
    private boolean connect(BluetoothDevice device){
//        BluetoothSocket socket = device.createRfcommSocketToServiceRecord(DEFAULT_UUID);
//        mCurrentSocket = (BluetoothSocket) ReflectHelper.callDeclaredMethod(device, "createRfcommSocket",
//                                                new Class<?>[]{int.class}, new Object[]{1});
//        mCurrentSocket.connect();

        cancelDiscover();
        LogUtil.i("czw_bluetooth", "connect--->连接设备，" + device.getName()+"|"+device.getAddress());
        if(mHeadsetService == null)
            return false;

        boolean rs = (boolean) ReflectHelper.callDeclaredMethod(mHeadsetService, "connect",
                                new Class<?>[]{BluetoothDevice.class},
                                new Object[]{device});
        return rs;
    }

    //断开耳机连接
    private boolean disconnect(BluetoothDevice device){
        LogUtil.i("czw_bluetooth", "disconnect--->断开设备，" + device.getName()+"|"+device.getAddress());

        if(mHeadsetService == null)
            return false;

        boolean rs = (boolean) ReflectHelper.callDeclaredMethod(mHeadsetService, "disconnect",
                new Class<?>[]{BluetoothDevice.class},
                new Object[]{device});

        if(mA2dpService != null){
            boolean rs2 = (boolean) ReflectHelper.callDeclaredMethod(mA2dpService, "disconnect",
                    new Class<?>[]{BluetoothDevice.class},
                    new Object[]{device});

            return (rs && rs2);
        }

        return rs;
    }

    public void startDiscoverDevices(){
        LogUtil.i("czw_bluetooth", "开始扫描蓝牙设备");
        if(!btAdapter.isDiscovering()){
            btAdapter.startDiscovery();
        }
    }

    public void cancelDiscover(){
        LogUtil.i("czw_bluetooth", "停止扫描蓝牙设备");
        if(btAdapter.isDiscovering()){
            btAdapter.cancelDiscovery();
        }
    }

    public interface OnProfileChangeListener {
        public void onServiceConnected(int profile, BluetoothProfile proxy);
        public void onServiceDisconnected(int profile);
        public void onDestory();
    }
}
